using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace Beetle;

public class TcpServer : IDisposable
{
	private EventTcpServerError m_a;

	private bool m_b;

	private object m_c = new object();

	private n m_d;

	private int e = 255;

	private ChannelCreatingArgs f = new ChannelCreatingArgs();

	internal static string g = "73HWrM6iCrk=";

	private Socket h;

	private g i;

	private Queue<n> j = new Queue<n>(1024);

	private Dictionary<Type, IIPFiler> k = new Dictionary<Type, IIPFiler>();

	private DetectTimeoutHandler l;

	private EventChannglCreating m;

	private bool n;

	public bool EnabledVariant;

	internal Dictionary<long, IChannel> o;

	private IPEndPoint p;

	private EventChannelConnected q;

	private EventChannelDisposed r;

	private long s;

	public static ObjectPool<SocketAsyncEventArgs> SocketAsyncEventArgsPools = new ObjectPool<SocketAsyncEventArgs>(1024);

	private bool t;

	private object u = new object();

	[CompilerGenerated]
	private bool v;

	[CompilerGenerated]
	private bool w;

	[CompilerGenerated]
	private bool x;

	[CompilerGenerated]
	private bool y;

	[CompilerGenerated]
	private Encoding z;

	[CompilerGenerated]
	private bool aa;

	public bool LittleEndian
	{
		[CompilerGenerated]
		get
		{
			return v;
		}
		[CompilerGenerated]
		set
		{
			v = value;
		}
	}

	public bool EnabledReceiveQueue
	{
		[CompilerGenerated]
		get
		{
			return w;
		}
		[CompilerGenerated]
		set
		{
			w = value;
		}
	}

	public bool EnabledSendQueue
	{
		[CompilerGenerated]
		get
		{
			return x;
		}
		[CompilerGenerated]
		set
		{
			x = value;
		}
	}

	public bool EnabledWorkQueue
	{
		[CompilerGenerated]
		get
		{
			return y;
		}
		[CompilerGenerated]
		set
		{
			y = value;
		}
	}

	public bool IsRunning => n;

	public DetectTimeoutHandler DetectHandler => l;

	public int QueueConnects => j.Count;

	public Socket Socket => h;

	public Encoding Coding
	{
		[CompilerGenerated]
		get
		{
			return z;
		}
		[CompilerGenerated]
		set
		{
			z = value;
		}
	}

	public long OnlineVersion => s;

	public bool EnabledChannelSendCompeletedEvent
	{
		[CompilerGenerated]
		get
		{
			return aa;
		}
		[CompilerGenerated]
		set
		{
			aa = value;
		}
	}

	public int Count => d();

	public event EventTcpServerError Error
	{
		add
		{
			EventTcpServerError eventTcpServerError = this.m_a;
			EventTcpServerError eventTcpServerError2;
			do
			{
				eventTcpServerError2 = eventTcpServerError;
				EventTcpServerError value2 = (EventTcpServerError)Delegate.Combine(eventTcpServerError2, value);
				eventTcpServerError = Interlocked.CompareExchange(ref this.m_a, value2, eventTcpServerError2);
			}
			while ((object)eventTcpServerError != eventTcpServerError2);
		}
		remove
		{
			EventTcpServerError eventTcpServerError = this.m_a;
			EventTcpServerError eventTcpServerError2;
			do
			{
				eventTcpServerError2 = eventTcpServerError;
				EventTcpServerError value2 = (EventTcpServerError)Delegate.Remove(eventTcpServerError2, value);
				eventTcpServerError = Interlocked.CompareExchange(ref this.m_a, value2, eventTcpServerError2);
			}
			while ((object)eventTcpServerError != eventTcpServerError2);
		}
	}

	public event EventChannglCreating ChannelCreating
	{
		add
		{
			EventChannglCreating eventChannglCreating = m;
			EventChannglCreating eventChannglCreating2;
			do
			{
				eventChannglCreating2 = eventChannglCreating;
				EventChannglCreating value2 = (EventChannglCreating)Delegate.Combine(eventChannglCreating2, value);
				eventChannglCreating = Interlocked.CompareExchange(ref m, value2, eventChannglCreating2);
			}
			while ((object)eventChannglCreating != eventChannglCreating2);
		}
		remove
		{
			EventChannglCreating eventChannglCreating = m;
			EventChannglCreating eventChannglCreating2;
			do
			{
				eventChannglCreating2 = eventChannglCreating;
				EventChannglCreating value2 = (EventChannglCreating)Delegate.Remove(eventChannglCreating2, value);
				eventChannglCreating = Interlocked.CompareExchange(ref m, value2, eventChannglCreating2);
			}
			while ((object)eventChannglCreating != eventChannglCreating2);
		}
	}

	public event EventChannelConnected ChannelConnected
	{
		add
		{
			EventChannelConnected eventChannelConnected = q;
			EventChannelConnected eventChannelConnected2;
			do
			{
				eventChannelConnected2 = eventChannelConnected;
				EventChannelConnected value2 = (EventChannelConnected)Delegate.Combine(eventChannelConnected2, value);
				eventChannelConnected = Interlocked.CompareExchange(ref q, value2, eventChannelConnected2);
			}
			while ((object)eventChannelConnected != eventChannelConnected2);
		}
		remove
		{
			EventChannelConnected eventChannelConnected = q;
			EventChannelConnected eventChannelConnected2;
			do
			{
				eventChannelConnected2 = eventChannelConnected;
				EventChannelConnected value2 = (EventChannelConnected)Delegate.Remove(eventChannelConnected2, value);
				eventChannelConnected = Interlocked.CompareExchange(ref q, value2, eventChannelConnected2);
			}
			while ((object)eventChannelConnected != eventChannelConnected2);
		}
	}

	public event EventChannelDisposed ChannelDisposed
	{
		add
		{
			EventChannelDisposed eventChannelDisposed = r;
			EventChannelDisposed eventChannelDisposed2;
			do
			{
				eventChannelDisposed2 = eventChannelDisposed;
				EventChannelDisposed value2 = (EventChannelDisposed)Delegate.Combine(eventChannelDisposed2, value);
				eventChannelDisposed = Interlocked.CompareExchange(ref r, value2, eventChannelDisposed2);
			}
			while ((object)eventChannelDisposed != eventChannelDisposed2);
		}
		remove
		{
			EventChannelDisposed eventChannelDisposed = r;
			EventChannelDisposed eventChannelDisposed2;
			do
			{
				eventChannelDisposed2 = eventChannelDisposed;
				EventChannelDisposed value2 = (EventChannelDisposed)Delegate.Remove(eventChannelDisposed2, value);
				eventChannelDisposed = Interlocked.CompareExchange(ref r, value2, eventChannelDisposed2);
			}
			while ((object)eventChannelDisposed != eventChannelDisposed2);
		}
	}

	public TcpServer()
	{
		Coding = Encoding.UTF8;
		o = new Dictionary<long, IChannel>(TcpUtils.Connections);
		EnabledChannelSendCompeletedEvent = false;
		l = new DetectTimeoutHandler();
		l.Server = this;
		i = global::g.g();
		EnabledReceiveQueue = TcpUtils.EnabledReceiveQueue;
		EnabledSendQueue = TcpUtils.EnabledSendQueue;
		EnabledWorkQueue = TcpUtils.EnabledWorkQueue;
		LittleEndian = true;
	}

	protected virtual void OnError(TcpServerErrorArgs e)
	{
		try
		{
			if (this.m_a != null)
			{
				this.m_a(this, e);
			}
		}
		catch
		{
		}
	}

	private void b(n A_0)
	{
		lock (j)
		{
			j.Enqueue(A_0);
		}
	}

	private n c()
	{
		lock (j)
		{
			if (j.Count > 0)
			{
				return j.Dequeue();
			}
			return null;
		}
	}

	public void SetFilter<T>() where T : IIPFiler, new()
	{
		lock (k)
		{
			k[typeof(T)] = new T();
		}
	}

	public T GetFilter<T>() where T : IIPFiler, new()
	{
		lock (k)
		{
			Type typeFromHandle = typeof(T);
			if (!k.ContainsKey(typeFromHandle))
			{
				k.Add(typeFromHandle, new T());
			}
			return (T)k[typeFromHandle];
		}
	}

	private void b(IChannel A_0)
	{
		lock (this.m_c)
		{
			o.Remove(A_0.ClientID);
			s++;
		}
	}

	private void a(IChannel A_0)
	{
		lock (this.m_c)
		{
			o.Add(A_0.ClientID, A_0);
			s++;
			((aq)A_0).aq = ((aq)A_0).f > (int)A_0["_data"];
		}
	}

	public IChannel GetClient(long id)
	{
		o.TryGetValue(id, out var value);
		return value;
	}

	public IChannel[] GetOnlines()
	{
		lock (this.m_c)
		{
			try
			{
				aq[] array = new aq[o.Count];
				o.Values.CopyTo(array, 0);
				return array;
			}
			catch (Exception a_)
			{
				a(a_);
				return new aq[0];
			}
		}
	}

	public void GetOnlines(OnlineSegment os)
	{
		lock (this.m_c)
		{
			try
			{
				if (os.OnlineVersion != OnlineVersion)
				{
					Dictionary<long, IChannel>.ValueCollection values = o.Values;
					values.CopyTo(os.Channels, 0);
					os.Count = o.Count;
					os.OnlineVersion = OnlineVersion;
				}
			}
			catch (Exception a_)
			{
				a(a_);
			}
		}
	}

	private void a(Exception A_0)
	{
		TcpServerErrorArgs tcpServerErrorArgs = new TcpServerErrorArgs();
		tcpServerErrorArgs.Error = A_0;
		try
		{
			OnError(tcpServerErrorArgs);
		}
		catch
		{
		}
	}

	public IChannel FindClient(long id, string name)
	{
		IChannel[] onlines = GetOnlines();
		for (int i = 0; i < onlines.Length; i++)
		{
			aq aq = (aq)onlines[i];
			if (id == aq.get_ClientID() || (!string.IsNullOrEmpty(name) && aq.get_Name() == name))
			{
				return aq;
			}
		}
		return null;
	}

	protected void OnConnected(IChannel e)
	{
		try
		{
			a(e);
			((aq)e).a(this);
			e.ChannelDisposed += OnClientDisposed;
			if (q != null)
			{
				q(this, new ChannelDisposedEventArgs
				{
					Channel = e,
					Clean = true
				});
			}
		}
		catch (Exception ex)
		{
			_ = ex.Message;
			a(ex);
		}
	}

	protected void OnClientDisposed(object source, ChannelDisposedEventArgs e)
	{
		try
		{
			((aq)e.Channel).a((TcpServer)null);
			b(e.Channel);
			if (r != null)
			{
				r(this, e);
			}
		}
		catch (Exception a_)
		{
			a(a_);
		}
	}

	protected void OnChannelCreating(ChannelCreatingArgs e)
	{
		if (m != null)
		{
			m(this, f);
		}
		e.Cancel = d() >= this.e;
	}

	public void Open(IPEndPoint ipendpoint)
	{
		Open(ipendpoint, 100);
	}

	public void Open(IPEndPoint ipendpoint, int listens)
	{
		if (!TcpUtils.a)
		{
			throw NetTcpException.NotInitialize();
		}
		p = ipendpoint;
		if (h != null)
		{
			Dispose();
		}
		h = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		Socket.Bind(ipendpoint);
		Socket.Listen(listens);
		n = true;
		ThreadPool.QueueUserWorkItem(b);
		ThreadPool.QueueUserWorkItem(a);
	}

	private void a(Socket A_0)
	{
		try
		{
			A_0.Disconnect(reuseSocket: false);
		}
		catch
		{
		}
		ReleaseSocket(A_0);
	}

	private int b()
	{
		return GetHashCode();
	}

	private void b(object A_0)
	{
		while (n)
		{
			try
			{
				this.m_d = c();
				if (this.m_d != null)
				{
					f.Cancel = false;
					f.Socket = this.m_d.b;
					f.Server = this;
					if (!i.a(a, this.m_d, d(), out e))
					{
						a(this.m_d.b);
						continue;
					}
					OnChannelCreating(f);
					if (!f.Cancel)
					{
						a(this.m_d);
					}
					else
					{
						a(this.m_d.b);
					}
					global::l.a(b(), o.Count);
				}
				else
				{
					Thread.Sleep(10);
				}
			}
			catch (Exception a_)
			{
				a(a_);
			}
		}
	}

	private bool a()
	{
		return o.Count < global::o.a;
	}

	private void a(object A_0)
	{
		try
		{
			bool flag = true;
			while (n && flag && !t)
			{
				SocketAsyncEventArgs socketAsyncEventArgs = SocketAsyncEventArgsPools.Pop();
				socketAsyncEventArgs.Completed += b;
				try
				{
					flag = !Socket.AcceptAsync(socketAsyncEventArgs);
					this.m_b = true;
				}
				catch (SocketException a_)
				{
					a(a_);
					break;
				}
				catch (ObjectDisposedException a_2)
				{
					a(a_2);
					break;
				}
				if (flag)
				{
					a(socketAsyncEventArgs);
				}
			}
		}
		catch (Exception a_3)
		{
			a(a_3);
		}
	}

	private void b(object A_0, SocketAsyncEventArgs A_1)
	{
		a(A_1);
		a((object)null);
	}

	private void a(SocketAsyncEventArgs A_0)
	{
		try
		{
			if (A_0.SocketError == SocketError.Success && !t)
			{
				n n = new n();
				n.b = A_0.AcceptSocket;
				b(n);
			}
			else
			{
				ReleaseSocket(A_0.AcceptSocket);
			}
			A_0.AcceptSocket = null;
		}
		catch (Exception a_)
		{
			a(a_);
		}
		finally
		{
			global::l.a(b(), o.Count);
			this.m_b = false;
			A_0.Completed -= b;
			SocketAsyncEventArgsPools.Push(A_0);
		}
	}

	private void a(n A_0)
	{
		aq aq = null;
		bool flag = true;
		if (k.Count > 0)
		{
			foreach (KeyValuePair<Type, IIPFiler> item in k)
			{
				flag = item.Value.Execute((IPEndPoint)A_0.b.RemoteEndPoint);
				if (!flag)
				{
					break;
				}
			}
		}
		if (flag)
		{
			aq = new aq(A_0.b);
			aq.set_LittleEndian(LittleEndian);
			aq.aa = EnabledVariant;
			a(aq);
			aq.m = EnabledChannelSendCompeletedEvent;
			aq.p = EnabledReceiveQueue;
			aq.q = EnabledSendQueue;
			aq.r = EnabledWorkQueue;
			OnConnected(aq);
		}
		else
		{
			A_0.b.Shutdown(SocketShutdown.Both);
			A_0.b.Close();
		}
	}

	public static void ReleaseSocket(Socket socket)
	{
		if (socket != null)
		{
			try
			{
				socket?.Shutdown(SocketShutdown.Both);
			}
			catch
			{
			}
			try
			{
				socket?.Close();
			}
			catch
			{
			}
		}
	}

	public void Open(int port)
	{
		Open(new IPEndPoint(IPAddress.Any, port));
	}

	public void Open(string ip, int port)
	{
		Open(ip, port, 100);
	}

	public void Open(string ip, int port, int listens)
	{
		Open(new IPEndPoint(IPAddress.Parse(ip), port), listens);
	}

	public static void SetKeepAliveValues(Socket socket, uint first, uint interval)
	{
		byte[] array = new byte[Marshal.SizeOf((object)first) * 3];
		BitConverter.GetBytes(1u).CopyTo(array, 0);
		BitConverter.GetBytes(first).CopyTo(array, Marshal.SizeOf((object)first));
		BitConverter.GetBytes(interval).CopyTo(array, Marshal.SizeOf((object)first) * 2);
		socket.IOControl(IOControlCode.KeepAliveValues, array, null);
	}

	public static IChannel CreateClient(string ip, int port)
	{
		return CreateClient(new IPEndPoint(IPAddress.Parse(ip), port));
	}

	public static IChannel CreateClient(IPAddress ip, int port)
	{
		return CreateClient(new IPEndPoint(ip, port));
	}

	public static IChannel CreateClient(IPEndPoint endpoint)
	{
		Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		socket.Connect(endpoint);
		return new aq(socket);
	}

	public static IChannel CreateClient<T>(string ip, int port, EventPacketRecievMessage receive) where T : Package
	{
		return CreateClient<T>(new IPEndPoint(IPAddress.Parse(ip), port), receive);
	}

	public static IChannel CreateClient<T>(IPAddress ip, int port, EventPacketRecievMessage receive) where T : Package
	{
		return CreateClient<T>(new IPEndPoint(ip, port), receive);
	}

	public static IChannel CreateClient<T>(IPEndPoint endpoint, EventPacketRecievMessage receive) where T : Package
	{
		if (!TcpUtils.a)
		{
			throw NetTcpException.NotInitialize();
		}
		Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		socket.Connect(endpoint);
		aq aq = new aq(socket);
		aq.SetPackage<T>().ReceiveMessage = receive;
		return aq;
	}

	public static void CreateClientAsync(string ip, int port, Action<CreateChannelArgs> result)
	{
		CreateClientAsync(IPAddress.Parse(ip), port, result);
	}

	public static void CreateClientAsync(IPAddress ip, int port, Action<CreateChannelArgs> result)
	{
		CreateClientAsync(new IPEndPoint(ip, port), result);
	}

	public static void CreateClientAsync(IPEndPoint endpoint, Action<CreateChannelArgs> result)
	{
		if (!TcpUtils.a)
		{
			throw NetTcpException.NotInitialize();
		}
		SocketAsyncEventArgs socketAsyncEventArgs = SocketAsyncEventArgsPools.Pop();
		socketAsyncEventArgs.Completed += a;
		try
		{
			socketAsyncEventArgs.UserToken = result;
			Socket socket2 = (socketAsyncEventArgs.AcceptSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp));
			socketAsyncEventArgs.RemoteEndPoint = endpoint;
			if (!socket2.ConnectAsync(socketAsyncEventArgs))
			{
				a(null, socketAsyncEventArgs);
			}
		}
		catch (Exception ex)
		{
			socketAsyncEventArgs.Completed -= a;
			SocketAsyncEventArgsPools.Push(socketAsyncEventArgs);
			throw ex;
		}
	}

	public void Pause()
	{
		lock (this.m_c)
		{
			if (!t)
			{
				t = true;
			}
		}
	}

	public void Resume()
	{
		lock (this.m_c)
		{
			if (t)
			{
				t = false;
				if (!this.m_b)
				{
					ThreadPool.QueueUserWorkItem(a);
				}
			}
		}
	}

	internal int d()
	{
		return o.Count;
	}

	private static void a(object A_0, SocketAsyncEventArgs A_1)
	{
		try
		{
			CreateChannelArgs createChannelArgs = new CreateChannelArgs();
			createChannelArgs.Error = A_1.SocketError;
			if (A_1.SocketError == SocketError.Success)
			{
				createChannelArgs.Channel = new aq(A_1.AcceptSocket);
			}
			Action<CreateChannelArgs> action = (Action<CreateChannelArgs>)A_1.UserToken;
			action(createChannelArgs);
		}
		catch
		{
		}
		finally
		{
			A_1.Completed -= a;
			SocketAsyncEventArgsPools.Push(A_1);
		}
	}

	internal void a(aq A_0)
	{
		A_0.f = o.Count;
		A_0.set_Item("_data", e);
	}

	public void Dispose()
	{
		lock (this)
		{
			if (n)
			{
				DetectHandler.Server = null;
				n = false;
				IChannel[] onlines = GetOnlines();
				for (int i = 0; i < onlines.Length; i++)
				{
					aq aq = (aq)onlines[i];
					aq.j = "Server Close!";
					aq.Dispose();
				}
				o.Clear();
				if (Socket != null)
				{
					ReleaseSocket(Socket);
					h = null;
				}
				lock (j)
				{
					j.Clear();
				}
				f.Server = null;
				f = null;
			}
		}
	}
}
